#include "queue.h"

QueueInfo g_queueInfo[QUEUE_MAX];

// 初始化队列
void QueueInit()
{
    for (unsigned char i = 0; i < QUEUE_MAX; i++)
    {
        g_queueInfo[i].cur_len = 0;
        g_queueInfo[i].max_len = 0;
        g_queueInfo[i].item_size = 0;
        g_queueInfo[i].id = 0xff;
    }
}
// 创建队列
char QueueCreate(unsigned char *id, unsigned short item_size, unsigned int len)
{
    for (unsigned char i = 0; i < QUEUE_MAX; i++)
    {
        if (g_queueInfo[i].id == 0xff)
        {
            // 设置队列最大长度
            g_queueInfo[i].max_len = len;
            // 设置每个条目的大小
            g_queueInfo[i].item_size = item_size;
            // 设置队列id
            *id = i;
            g_queueInfo[i].id = i;
            // 初始化队列头
            LOS_ListInit(&g_queueInfo[i].head);
            return 0;
        }
    }
    printf("%s line %d error : no queue available, please free any queue or modify macro QUEUE_MAX in queue.h\n", __func__, __LINE__);
    return FAILED;
}
// 出队
char QueueOut(unsigned char id, char *data)
{
    if (id > QUEUE_MAX - 1)
    {
        return FAILED;
    }
    QUEUE_NODE *tmp;
    // 取第一个节点
    tmp = LOS_DL_LIST_ENTRY((&g_queueInfo[id].head)->pstNext, QUEUE_NODE, s_list);
    // 第一个节点是head，则无数据
    if (&(tmp->s_list) == &g_queueInfo[id].head)
        return FAILED;
    // 提取数据
    if (data == NULL)
        return FAILED;
    //memcpy(data, tmp->user_data, strlen(tmp->user_data));
    //printf("%d %d\n", strlen(tmp->user_data), g_queueInfo[id].item_size);
    memcpy(data, tmp->user_data, g_queueInfo[id].item_size);
    // 删除节点
    LOS_ListDelete(&(tmp->s_list));
    // 释放内存
    free(tmp->user_data);
    free(tmp);
    // 计数器减1
    g_queueInfo[id].cur_len--;
    // 退出
    return 0;
}
// 入队
char QueueIn(unsigned char id, char *data)
{
    if (id > QUEUE_MAX - 1)
    {
        return FAILED;
    }
    QUEUE_NODE *tmp;
    // 申请内存
    tmp = (QUEUE_NODE *)malloc(sizeof(QUEUE_NODE));
    if (tmp == NULL)
    {
        printf("%s line %d error : malloc queue node failed...\n", __func__, __LINE__);
        return FAILED;
    }
    tmp->user_data = (char *)malloc(g_queueInfo[id].item_size);
    if (tmp->user_data == NULL)
    {
        printf("%s line %d error : malloc user data failed...\n", __func__, __LINE__);
        return FAILED;
    }
    // 超过总长度，删除第一个节点
    if (g_queueInfo[id].cur_len >= g_queueInfo[id].max_len)
    {
        QueueOut(id, NULL);
    }
    // 复制数据
    memcpy(tmp->user_data, data, g_queueInfo[id].item_size);
    // 插入节点
    LOS_ListTailInsert(&g_queueInfo[id].head, &(tmp->s_list));
    // 计数器加1
    g_queueInfo[id].cur_len++;
    return 0;
}
// 清除队列
char QueueClear(unsigned char id)
{
    if (id > QUEUE_MAX - 1)
    {
        return FAILED;
    }
    QUEUE_NODE *tmp, *node;
    // 遍历
    LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[id].head, QUEUE_NODE, s_list)
    {
        // 找到当前节点的前驱
        node = LOS_DL_LIST_ENTRY(tmp->s_list.pstPrev, QUEUE_NODE, s_list);
        // 删除节点
        LOS_ListDelete(&(tmp->s_list));
        // 释放内存
        free(tmp->user_data);
        free(tmp);
        // 由于当前节点被删除，因此tmp要重新赋值，这样tmp->s_list.pstNext才有效
        tmp = node;
    }
    g_queueInfo[id].cur_len = 0;
    return 0;
}

char QueueDestroy(unsigned char id)
{
    if (id > QUEUE_MAX - 1)
    {
        return FAILED;
    }
    QueueClear(id);
    // 队列回归原始状态
    g_queueInfo[id].max_len = 0;
    g_queueInfo[id].item_size = 0;
    g_queueInfo[id].id = 0xff;
    g_queueInfo[id].head.pstNext = NULL;
    g_queueInfo[id].head.pstPrev = NULL;
    return 0;
}

#if 0
int main(int argc, char **argv)
{
    queue_init();
    USER_DATA d1, d2, d3, d4, d5;
    d1.buf = 1;
    d2.buf = 2;
    unsigned short id;
    queue_create(&id, 2);
    queue_in(id, &d1);
    queue_in(id, &d2);
    queue_out(id, &d3);
    queue_out(id, &d4);
    queue_out(id, &d5);
    queue_clear(id);
    printf("%d %d\n", d3.buf, d4.buf);
    queue_out(id, &d5);
}
#endif